﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LeeAnn.Framework;
using LeeAnn.FeedForward;

namespace LeeAnn
{
    public class FeedForwardAnn: AnnFramework
    {
        public int Width, Height;
        private int curMaxNeuron, curNeuron, curMaxWeight, curWeight = 0;
        private int curRewards, curPunishments, lastRewards, lastPunishments = 0;
        private double curTestScore = 0;
        public int LifetimeRewards{get;set;} 
        public int LifetimePunishments { get; set;}

        public FeedForwardAnn(int width, int height)
        {
            Width = width;
            Height = height;
            curMaxNeuron = 0;
            curNeuron = 0;
            LifetimeRewards = 0;
            LifetimePunishments = 0;
            DesignNetwork();

        }
        override
        public void Update()
        {
            int theCount = 0;
            bool gotInput = false;
            while (theCount < Outputs.Count)
            {
                if (!gotInput)
                {
                    for (int i = 0; i < Inputs.Count; i++)
                    {
                        if (InputOutputNeurons[Inputs[i]].HasInputs)
                        {
                            InputOutputNeurons[Inputs[i]].Push(this);
                            gotInput = true;
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < Neurons.Count; i++)
                    {

                        if (Neurons[i].HasInputs)
                        {
                            Neurons[i].Push(this);
                        }
                    }
                    for (int i = 0; i < Outputs.Count; i++)
                    {
                        if (InputOutputNeurons[Outputs[i]].HasInputs)
                        {
                            InputOutputNeurons[Outputs[i]].Push(this);
                            theCount++;
                        }
                    }
                }
            }
        }
        override
        public void DesignNetwork()
        {
            for(int y=0;y<Height;y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Neuron n = new Neuron();
                    n.Position = new Position3D(x,y,0);
                    n.CalculateEvent += new Neuron.CalculateIODelegate(CalculateEvent);
                    Neurons.Add(n);
                }
            }
            int i = 0;
            for (int y = 1; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    for (int g = 0; g < Width; g++)
                    {
                        FeedForwardNeuronPlaceholder ff = new FeedForwardNeuronPlaceholder(new Position3D(g, y, 0));
                        Neurons[i].AddOutput(ff);
                    }
                    i++;
                }
            }
            
        }
        public void Punish()
        {
            for (int i = 0; i < Neurons.Count; i++)
            {
                for (int w = 0; w < Neurons[i].Weights.Count; w++)
                {
                    //If the connections strong, weaken it
                    if (Neurons[i].Weights[w] >= .25)
                    {
                        Neurons[i].Weights[w] = Maths.Clamp<double>(Neurons[i].Weights[w] - .001, 1, -1);
                    }
                    //If the connections in between, randomize it
                    else if (Neurons[i].Weights[w] > -.25 && Neurons[i].Weights[w] < .25)
                    {
                        Neurons[i].Weights[w] = Maths.RandomClamped(-1, 1);
                    }
                    //If the connections weak, strengthen it
                    else if (Neurons[i].Weights[w] <= -.25)
                    {
                        Neurons[i].Weights[w] = Maths.Clamp<double>(Neurons[i].Weights[w] + .001, 1, -1);
                    }
                }
            }
        }
        public void Reward()
        { 
            for (int i = 0; i < Neurons.Count; i++)
            {
                for (int w = 0; w < Neurons[i].Weights.Count; w++)
                {
                    //If the connections strong, strengthen it
                    if (Neurons[i].Weights[w]>= .25)
                    {
                        Neurons[i].Weights[w] = Maths.Clamp<double>(Neurons[i].Weights[w] + .001,1,-1);
                    }
                    //If the connections in between, randomize it
                    else if (Neurons[i].Weights[w] > -.25 && Neurons[i].Weights[w] < .25)
                    {
                        Neurons[i].Weights[w] = Maths.RandomClamped(-1, 1);
                    }
                    //If the connections weak, weaken it
                    else if (Neurons[i].Weights[w] <= -.25)
                    {
                        Neurons[i].Weights[w] = Maths.Clamp<double>(Neurons[i].Weights[w] - .001, 1, -1);
                    }
                }
            }
        }
        public void CalculateEvent(List<double> inputs, List<double> inputweights, ref double outputData, AnnFramework frame)
        {
            //Get Activation value
            double activation = 0;
            for (int i = 0; i < inputs.Count; i++)
            {
                activation += inputs[i] * inputweights[i];
            }
            activation += inputweights[inputweights.Count-1] * -1;
            //Sigmoid function
            double o = (1 / (1 + Math.Exp(-activation / 1.0)));
            outputData = o;
        }
        
    }
}
